﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Область СлужебныйПрограммныйИнтерфейс

// Проверяет, включено ли регламентное задание по функциональным опциям.
//
// Параметры:
//  Задание - ОбъектМетаданныхРегламентноеЗадание - регламентное задание.
//  ЗависимостиЗаданий - ТаблицаЗначений - таблица зависимостей регламентных
//    заданий, полученная методом РегламентныеЗаданияСлужебный.РегламентныеЗаданияЗависимыеОтФункциональныхОпций.
//    Если не указано, получается автоматически.
//
// Возвращаемое значение:
//  Булево - Истина, если регламентное задание используется.
//
Функция РегламентноеЗаданиеДоступноПоФункциональнымОпциям(Задание, ЗависимостиЗаданий = Неопределено) Экспорт
	
	Если ЗависимостиЗаданий = Неопределено Тогда
		ЗависимостиЗаданий = РегламентныеЗаданияЗависимыеОтФункциональныхОпций();
	КонецЕсли;
	
	ОтключитьВПодчиненномУзлеРИБ = Ложь;
	ОтключитьВАвтономномРабочемМесте = Ложь;
	Использование                = Неопределено;
	ЭтоПодчиненныйУзелРИБ        = ОбщегоНазначения.ЭтоПодчиненныйУзелРИБ();
	ЭтоРазделенныйРежим          = ОбщегоНазначения.РазделениеВключено();
	ЭтоАвтономноеРабочееМесто = ОбщегоНазначения.ЭтоАвтономноеРабочееМесто();
	
	НайденныеСтроки = ЗависимостиЗаданий.НайтиСтроки(Новый Структура("РегламентноеЗадание", Задание));
	
	Для Каждого СтрокаЗависимости Из НайденныеСтроки Цикл
		Если ЭтоРазделенныйРежим И СтрокаЗависимости.ДоступноВМоделиСервиса = Ложь Тогда
			Возврат Ложь;
		КонецЕсли;
		
		ОтключитьВПодчиненномУзлеРИБ = (СтрокаЗависимости.ДоступноВПодчиненномУзлеРИБ = Ложь) И ЭтоПодчиненныйУзелРИБ;
		ОтключитьВАвтономномРабочемМесте = (СтрокаЗависимости.ДоступноВАвтономномРабочемМесте = Ложь) И ЭтоАвтономноеРабочееМесто;
		
		Если ОтключитьВПодчиненномУзлеРИБ Или ОтключитьВАвтономномРабочемМесте Тогда
			Возврат Ложь;
		КонецЕсли;
		
		Если СтрокаЗависимости.ФункциональнаяОпция = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		
		ЗначениеФО = ПолучитьФункциональнуюОпцию(СтрокаЗависимости.ФункциональнаяОпция.Имя);
		
		Если Использование = Неопределено Тогда
			Использование = ЗначениеФО;
		ИначеЕсли СтрокаЗависимости.ЗависимостьПоИ Тогда
			Использование = Использование И ЗначениеФО;
		Иначе
			Использование = Использование Или ЗначениеФО;
		КонецЕсли;
	КонецЦикла;
	
	Если Использование = Неопределено Тогда
		Возврат Истина;
	Иначе
		Возврат Использование;
	КонецЕсли;
	
КонецФункции

// Формирует таблицу зависимостей регламентных заданий от функциональных опций.
//
// Возвращаемое значение:
//  ТаблицаЗначений:
//    * РегламентноеЗадание - ОбъектМетаданныхРегламентноеЗадание - регламентное задание.
//    * ФункциональнаяОпция - ОбъектМетаданныхФункциональнаяОпция - функциональная опция,
//        от которой зависит регламентное задание.
//    * ЗависимостьПоИ      - Булево - если регламентное задание зависит более, чем
//        от одной функциональной опции и его необходимо включать только тогда,
//        когда все функциональные опции включены, то следует указывать Истина
//        для каждой зависимости.
//        По умолчанию Ложь - если хотя бы одна функциональная опция включена,
//        то регламентное задание тоже включено.
//    * ВключатьПриВключенииФункциональнойОпции - Булево
//                                              - Неопределено - если Ложь, то при
//        включении функциональной опции регламентное задание не будет включаться. Значение
//        Неопределено соответствует значению Истина.
//        По умолчанию - неопределено.
//    * ДоступноВПодчиненномУзлеРИБ - Булево
//                                  - Неопределено - Истина или Неопределено, если регламентное
//        задание доступно в РИБ.
//        По умолчанию - неопределено.
//    * ДоступноВМоделиСервиса      - Булево
//                                  - Неопределено - Истина или Неопределено, если регламентное
//        задание доступно в модели сервиса.
//        По умолчанию - неопределено.
//    * РаботаетСВнешнимиРесурсами   - Булево - Истина, если регламентное задание работает
//        с внешними ресурсами (получение почты, синхронизация данных и т.п.).
//        По умолчанию - Ложь.
//
Функция РегламентныеЗаданияЗависимыеОтФункциональныхОпций() Экспорт
	
	Зависимости = Новый ТаблицаЗначений;
	Зависимости.Колонки.Добавить("РегламентноеЗадание");
	Зависимости.Колонки.Добавить("ФункциональнаяОпция");
	Зависимости.Колонки.Добавить("ЗависимостьПоИ", Новый ОписаниеТипов("Булево"));
	Зависимости.Колонки.Добавить("ДоступноВМоделиСервиса");
	Зависимости.Колонки.Добавить("ДоступноВПодчиненномУзлеРИБ");
	Зависимости.Колонки.Добавить("ВключатьПриВключенииФункциональнойОпции");
	Зависимости.Колонки.Добавить("ДоступноВАвтономномРабочемМесте");
	Зависимости.Колонки.Добавить("РаботаетСВнешнимиРесурсами",  Новый ОписаниеТипов("Булево"));
	Зависимости.Колонки.Добавить("Параметризуется",  Новый ОписаниеТипов("Булево"));
	
	ИнтеграцияПодсистемБСП.ПриОпределенииНастроекРегламентныхЗаданий(Зависимости);
	РегламентныеЗаданияПереопределяемый.ПриОпределенииНастроекРегламентныхЗаданий(Зависимости);
	
	Зависимости.Сортировать("РегламентноеЗадание");
	
	Возврат Зависимости;
	
КонецФункции

// Устанавливает признак использования регламентных заданий в информационной базе
// в зависимости от значений функциональных опций.
//
// Параметры:
//  ВключатьЗадания - Булево - если Истина, отключенные регламентные задания будут включаться
//                             при доступности по функциональным опциям. По умолчанию Ложь.
//
Процедура УстановитьИспользованиеРегламентныхЗаданийПоФункциональнымОпциям(ВключатьЗадания = Ложь) Экспорт
	
	ЭтоПодчиненныйУзелРИБ = ОбщегоНазначения.ЭтоПодчиненныйУзелРИБ();
	ЭтоАвтономноеРабочееМесто = ОбщегоНазначения.ЭтоАвтономноеРабочееМесто();
	
	ЗависимыеРегламентныеЗадания = РегламентныеЗаданияЗависимыеОтФункциональныхОпций();
	Задания = ЗависимыеРегламентныеЗадания.Скопировать(,"РегламентноеЗадание");
	Задания.Свернуть("РегламентноеЗадание");
	
	Для Каждого СтрокаЗадание Из Задания Цикл
		
		Использование                    = Неопределено;
		ОтключитьЗадание                 = Истина;
		ОтключитьВПодчиненномУзлеРИБ     = Ложь;
		ОтключитьВАвтономномРабочемМесте = Ложь;
		
		НайденныеСтроки = ЗависимыеРегламентныеЗадания.НайтиСтроки(Новый Структура("РегламентноеЗадание", СтрокаЗадание.РегламентноеЗадание));
		
		Для Каждого СтрокаЗависимости Из НайденныеСтроки Цикл
			ОтключитьВПодчиненномУзлеРИБ = (СтрокаЗависимости.ДоступноВПодчиненномУзлеРИБ = Ложь) И ЭтоПодчиненныйУзелРИБ;
			ОтключитьВАвтономномРабочемМесте = (СтрокаЗависимости.ДоступноВАвтономномРабочемМесте = Ложь) И ЭтоАвтономноеРабочееМесто;
			Если ОтключитьВПодчиненномУзлеРИБ Или ОтключитьВАвтономномРабочемМесте Тогда
				Использование = Ложь;
				Прервать;
			КонецЕсли;
			
			Если СтрокаЗависимости.ФункциональнаяОпция = Неопределено Тогда
				Продолжить;
			КонецЕсли;
			
			ЗначениеФО = ПолучитьФункциональнуюОпцию(СтрокаЗависимости.ФункциональнаяОпция.Имя);
			
			Если СтрокаЗависимости.ВключатьПриВключенииФункциональнойОпции = Ложь Тогда
				Если ОтключитьЗадание Тогда
					ОтключитьЗадание = Не ЗначениеФО;
				КонецЕсли;
				ЗначениеФО = Ложь;
			КонецЕсли;
			
			Если Использование = Неопределено Тогда
				Использование = ЗначениеФО;
			ИначеЕсли СтрокаЗависимости.ЗависимостьПоИ Тогда
				Использование = Использование И ЗначениеФО;
			Иначе
				Использование = Использование Или ЗначениеФО;
			КонецЕсли;
		КонецЦикла;
		
		Если Использование = Неопределено
			Или (Использование И Не ВключатьЗадания) // Автоматически при обновлении только отключаем регламентные задания.
			Или (Не Использование И Не ОтключитьЗадание) Тогда
			Продолжить;
		КонецЕсли;
		
		СписокЗаданий = РегламентныеЗаданияСервер.НайтиЗадания(Новый Структура("Метаданные", СтрокаЗадание.РегламентноеЗадание));
		Для Каждого РегламентноеЗадание Из СписокЗаданий Цикл
			ПараметрыЗадания = Новый Структура("Использование", Использование);
			РегламентныеЗаданияСервер.ИзменитьЗадание(РегламентноеЗадание, ПараметрыЗадания);
		КонецЦикла;
		
	КонецЦикла;
	
КонецПроцедуры

// Возвращает таблицу свойств фоновых заданий.
//  Структуру таблицы смотри в функции ПустаяТаблицаСвойствФоновыхЗаданий().
// 
// Параметры:
//  Отбор        - Структура - допустимые поля:
//                 Идентификатор, Ключ, Состояние, Начало, Конец,
//                 Наименование, ИмяМетода, РегламентноеЗадание. 
//
// Возвращаемое значение:
//   см. НовыеСвойстваФоновыхЗаданий
//
Функция СвойстваФоновыхЗаданий(Отбор = Неопределено) Экспорт
	
	ВызватьИсключениеЕслиНетПраваАдминистрирования();
	УстановитьПривилегированныйРежим(Истина);
	
	Таблица = НовыеСвойстваФоновыхЗаданий();
	
	Если ЗначениеЗаполнено(Отбор) И Отбор.Свойство("ПолучитьПоследнееФоновоеЗаданиеРегламентногоЗадания") Тогда
		Отбор.Удалить("ПолучитьПоследнееФоновоеЗаданиеРегламентногоЗадания");
		ПолучитьПоследнее = Истина;
	Иначе
		ПолучитьПоследнее = Ложь;
	КонецЕсли;
	
	РегламентноеЗадание = Неопределено;
	
	// Добавление истории фоновых заданий, полученных с сервера.
	Если ЗначениеЗаполнено(Отбор) И Отбор.Свойство("ИдентификаторРегламентногоЗадания") Тогда
		Если Отбор.ИдентификаторРегламентногоЗадания <> "" Тогда
			РегламентноеЗадание = РегламентныеЗадания.НайтиПоУникальномуИдентификатору(
				Новый УникальныйИдентификатор(Отбор.ИдентификаторРегламентногоЗадания));
			
			ВсеФоновыеЗадания       = Новый Массив;
			ЗапущенныеАвтоматически = Новый Массив;
			ТекущийОтбор      = Новый Структура("Ключ", Отбор.ИдентификаторРегламентногоЗадания);
			ЗапущенныеВручную = ФоновыеЗадания.ПолучитьФоновыеЗадания(ТекущийОтбор);
			
			Если РегламентноеЗадание <> Неопределено Тогда
				ПоследнееФоновоеЗадание = РегламентноеЗадание.ПоследнееЗадание;
				ТекущийОтбор            = Новый Структура("РегламентноеЗадание", РегламентноеЗадание);
				ЗапущенныеАвтоматически = ФоновыеЗадания.ПолучитьФоновыеЗадания(ТекущийОтбор);
			КонецЕсли;
			
			ОбщегоНазначенияКлиентСервер.ДополнитьМассив(ВсеФоновыеЗадания, ЗапущенныеВручную);
			ОбщегоНазначенияКлиентСервер.ДополнитьМассив(ВсеФоновыеЗадания, ЗапущенныеАвтоматически);
			
			Если ПолучитьПоследнее Тогда
				ПоследнееФоновоеЗадание = РегламентныеЗаданияСервер.ПоследнееФоновоеЗаданиеВМассиве(ВсеФоновыеЗадания);
				
				Если ПоследнееФоновоеЗадание <> Неопределено Тогда
					МассивФоновыхЗаданий = Новый Массив;
					МассивФоновыхЗаданий.Добавить(ПоследнееФоновоеЗадание);
					ДобавитьСвойстваФоновыхЗаданий(МассивФоновыхЗаданий, Таблица);
				КонецЕсли;
				Возврат Таблица;
			КонецЕсли;
			ДобавитьСвойстваФоновыхЗаданий(ВсеФоновыеЗадания, Таблица);
		Иначе
			МассивФоновыхЗаданий = Новый Массив;
			ВсеИдентификаторыРегламентныхЗаданий = Новый Соответствие;
			Для каждого ТекущееЗадание Из РегламентныеЗадания.ПолучитьРегламентныеЗадания() Цикл
				ВсеИдентификаторыРегламентныхЗаданий.Вставить(
					Строка(ТекущееЗадание.УникальныйИдентификатор), Истина);
			КонецЦикла;
			ВсеФоновыеЗадания = ФоновыеЗадания.ПолучитьФоновыеЗадания();
			Для каждого ТекущееЗадание Из ВсеФоновыеЗадания Цикл
				Если ТекущееЗадание.РегламентноеЗадание = Неопределено
				   И ВсеИдентификаторыРегламентныхЗаданий[ТекущееЗадание.Ключ] = Неопределено Тогда
				
					МассивФоновыхЗаданий.Добавить(ТекущееЗадание);
				КонецЕсли;
			КонецЦикла;
			ДобавитьСвойстваФоновыхЗаданий(МассивФоновыхЗаданий, Таблица);
		КонецЕсли;
	Иначе
		Если НЕ ЗначениеЗаполнено(Отбор) Тогда
			МассивФоновыхЗаданий = ФоновыеЗадания.ПолучитьФоновыеЗадания();
		Иначе
			Если Отбор.Свойство("Идентификатор") Тогда
				Отбор.Вставить("УникальныйИдентификатор", Новый УникальныйИдентификатор(Отбор.Идентификатор));
				Отбор.Удалить("Идентификатор");
			КонецЕсли;
			МассивФоновыхЗаданий = ФоновыеЗадания.ПолучитьФоновыеЗадания(Отбор);
			Если Отбор.Свойство("УникальныйИдентификатор") Тогда
				Отбор.Вставить("Идентификатор", Строка(Отбор.УникальныйИдентификатор));
				Отбор.Удалить("УникальныйИдентификатор");
			КонецЕсли;
		КонецЕсли;
		ДобавитьСвойстваФоновыхЗаданий(МассивФоновыхЗаданий, Таблица);
	КонецЕсли;
	
	Если ЗначениеЗаполнено(Отбор) И Отбор.Свойство("ИдентификаторРегламентногоЗадания") Тогда
		РегламентныеЗаданияДляОбработки = Новый Массив;
		Если Отбор.ИдентификаторРегламентногоЗадания <> "" Тогда
			Если РегламентноеЗадание = Неопределено Тогда
				РегламентноеЗадание = РегламентныеЗадания.НайтиПоУникальномуИдентификатору(
					Новый УникальныйИдентификатор(Отбор.ИдентификаторРегламентногоЗадания));
			КонецЕсли;
			Если РегламентноеЗадание <> Неопределено Тогда
				РегламентныеЗаданияДляОбработки.Добавить(РегламентноеЗадание);
			КонецЕсли;
		КонецЕсли;
	Иначе
		РегламентныеЗаданияДляОбработки = РегламентныеЗадания.ПолучитьРегламентныеЗадания();
	КонецЕсли;
	
	Таблица.Сортировать("Начало Убыв, Конец Убыв");
	
	// Отбор фоновых заданий.
	Если ЗначениеЗаполнено(Отбор) Тогда
		Начало    = Неопределено;
		Конец     = Неопределено;
		Состояние = Неопределено;
		Если Отбор.Свойство("Начало") Тогда
			Начало = ?(ЗначениеЗаполнено(Отбор.Начало), Отбор.Начало, Неопределено);
			Отбор.Удалить("Начало");
		КонецЕсли;
		Если Отбор.Свойство("Конец") Тогда
			Конец = ?(ЗначениеЗаполнено(Отбор.Конец), Отбор.Конец, Неопределено);
			Отбор.Удалить("Конец");
		КонецЕсли;
		Если Отбор.Свойство("Состояние") Тогда
			Если ТипЗнч(Отбор.Состояние) = Тип("Массив") Тогда
				Состояние = Отбор.Состояние;
				Отбор.Удалить("Состояние");
			КонецЕсли;
		КонецЕсли;
		
		Если Отбор.Количество() <> 0 Тогда
			Строки = Таблица.НайтиСтроки(Отбор);
		Иначе
			Строки = Таблица;
		КонецЕсли;
		// Выполнение дополнительного отбора по периоду и состоянию (если отбор определен).
		НомерЭлемента = Строки.Количество() - 1;
		Пока НомерЭлемента >= 0 Цикл
			Если Начало    <> Неопределено И Начало > Строки[НомерЭлемента].Начало
				Или Конец     <> Неопределено И Конец  < ?(ЗначениеЗаполнено(Строки[НомерЭлемента].Конец), Строки[НомерЭлемента].Конец, ТекущаяДатаСеанса())
				Или Состояние <> Неопределено И Состояние.Найти(Строки[НомерЭлемента].Состояние) = Неопределено Тогда
				Строки.Удалить(НомерЭлемента);
			КонецЕсли;
			НомерЭлемента = НомерЭлемента - 1;
		КонецЦикла;
		// Удаление лишних строк из таблицы.
		Если ТипЗнч(Строки) = Тип("Массив") Тогда
			НомерСтроки = Таблица.Количество() - 1;
			Пока НомерСтроки >= 0 Цикл
				Если Строки.Найти(Таблица[НомерСтроки]) = Неопределено Тогда
					Таблица.Удалить(Таблица[НомерСтроки]);
				КонецЕсли;
				НомерСтроки = НомерСтроки - 1;
			КонецЦикла;
		КонецЕсли;
	КонецЕсли;
	
	Возврат Таблица;
	
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Обработчики подписок на события.

// Процедура включает/отключает созданные в ИБ регламентные задания
// при изменении функциональной опции.
//
// Параметры:
//  Источник - КонстантаМенеджерЗначения - константа хранения значения ФО.
//  Отказ    - Булево - отказ при записи константы.
//
Процедура ВключитьРегламентноеЗаданиеПриИзмененииФункциональнойОпции(Источник, Отказ) Экспорт
	
	Если Источник.ОбменДанными.Загрузка Тогда
		Возврат;
	КонецЕсли;
	
	УстановитьПривилегированныйРежим(Истина);
	ИзменитьИспользованиеРегламентныхЗаданийПоФункциональнымОпциям(Источник, Источник.Значение);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Обработчики событий подсистем конфигурации.

// См. ВыгрузкаЗагрузкаДанныхПереопределяемый.ПослеЗагрузкиДанных.
Процедура ПослеЗагрузкиДанных(Контейнер) Экспорт
	
	БлокировкаРаботыСВнешнимиРесурсами.ПослеЗагрузкиДанных(Контейнер);
	
КонецПроцедуры

// См. РаботаВМоделиСервисаПереопределяемый.ПриЗаполненииТаблицыПараметровИБ.
Процедура ПриЗаполненииТаблицыПараметровИБ(Знач ТаблицаПараметров) Экспорт
	
	Если ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда
		МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
		МодульРаботаВМоделиСервиса.ДобавитьКонстантуВТаблицуПараметровИБ(ТаблицаПараметров, "МаксимальнаяДлительностьВыполненияИсполняющегоФоновогоЗадания");
		МодульРаботаВМоделиСервиса.ДобавитьКонстантуВТаблицуПараметровИБ(ТаблицаПараметров, "МаксимальноеКоличествоИсполняющихФоновыхЗаданий");
	КонецЕсли;
	
КонецПроцедуры

// См. ОбновлениеИнформационнойБазыБСП.ПриДобавленииОбработчиковОбновления.
Процедура ПриДобавленииОбработчиковОбновления(Обработчики) Экспорт
	
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия = "2.3.3.12";
	Обработчик.НачальноеЗаполнение = Истина;
	Обработчик.РежимВыполнения = "Оперативно";
	Обработчик.Процедура = "БлокировкаРаботыСВнешнимиРесурсами.ОбновитьПараметрыБлокировкиРаботыСВнешнимиРесурсами";
	
КонецПроцедуры

// См. ОбменДаннымиПереопределяемый.ПриНастройкеПодчиненногоУзлаРИБ.
Процедура ПриНастройкеПодчиненногоУзлаРИБ() Экспорт
	
	УстановитьИспользованиеРегламентныхЗаданийПоФункциональнымОпциям();
	
КонецПроцедуры

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

Функция ЗначениеНастройки(ИмяНастройки) Экспорт
	
	Настройки = НастройкиПоУмолчанию();
	РегламентныеЗаданияПереопределяемый.ПриОпределенииНастроек(Настройки);
	
	Возврат Настройки[ИмяНастройки];
	
КонецФункции

// Содержит значения настроек по умолчанию.
//
// Возвращаемое значение:
//  Структура:
//    * РасположениеКомандыСнятияБлокировки - Строка - определяет расположение команды снятия
//                                                     блокировки работы с внешними ресурсами.
//
Функция НастройкиПоУмолчанию()
	
	НастройкиПодсистемы = Новый Структура;
	НастройкиПодсистемы.Вставить("РасположениеКомандыСнятияБлокировки",
		НСтр("ru = 'Блокировку также можно снять позднее в разделе <b>Администрирование - Обслуживание</b>.'"));
	
	Возврат НастройкиПодсистемы;
	
КонецФункции

// Вызывает исключение, если у пользователя нет права администрирования.
Процедура ВызватьИсключениеЕслиНетПраваАдминистрирования() Экспорт
	
	Если ОбщегоНазначения.РазделениеВключено()
		И ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
		Если НЕ Пользователи.ЭтоПолноправныйПользователь() Тогда
			ВызватьИсключение НСтр("ru = 'Нарушение прав доступа.'");
		КонецЕсли;
	Иначе
		Если НЕ ПривилегированныйРежим() Тогда
			ВыполнитьПроверкуПравДоступа("Администрирование", Метаданные);
		КонецЕсли;
	КонецЕсли;
	
КонецПроцедуры


// Параметры:
//  Параметры - Структура:
//     * Таблица - ТаблицаЗначений:
//          ** Идентификатор - Строка
//          ** Предопределенное - Булево
//          ** Ключ - Строка
//          ** Наименование - Строка
//          ** Использование - Булево
//          ** Расписание - Строка
//          ** ИнтервалПовтораПриАварийномЗавершении - Число
//          ** КоличествоПовторовПриАварийномЗавершении - Строка
//          ** УникальныйИдентификаторПоследнегоФЗ - Строка
//          ** СостояниеВыполнения - Строка
//          ** ДатаОкончания - Строка
//          ** ИмяПользователя - Строка
//          ** ИмяЗадания - Строка
//          ** Параметризуемое - Булево
//          ** ДатаНачала - Строка
//  АдресХранилища - Строка
//
Процедура СформироватьТаблицуРегламентныхЗаданий(Параметры, АдресХранилища) Экспорт
	
	ИдентификаторРегламентногоЗадания = Параметры.ИдентификаторРегламентногоЗадания;
	Таблица                           = Параметры.Таблица;
	ОтключенныеЗадания                = Параметры.ОтключенныеЗадания;
	
	// Обновление таблицы РегламентныеЗадания и списка СписокВыбора регламентного задания для отбора.
	ТекущиеЗадания = РегламентныеЗадания.ПолучитьРегламентныеЗадания();
	ОтключенныеЗадания.Очистить();
	
	ПараметрыРегламентныхЗаданий = РегламентныеЗаданияЗависимыеОтФункциональныхОпций();
	ПараметрыОтбора        = Новый Структура;
	ПараметризуемыеЗадания = Новый Массив;
	ПараметрыОтбора.Вставить("Параметризуется", Истина);
	РезультатПоиска = ПараметрыРегламентныхЗаданий.НайтиСтроки(ПараметрыОтбора);
	Для Каждого СтрокаРезультата Из РезультатПоиска Цикл
		ПараметризуемыеЗадания.Добавить(СтрокаРезультата.РегламентноеЗадание);
	КонецЦикла;
	
	ПодсистемаРаботаВМоделиСервиса = Метаданные.Подсистемы.СтандартныеПодсистемы.Подсистемы.Найти("РаботаВМоделиСервиса");
	Для Каждого ОбъектМетаданных Из Метаданные.РегламентныеЗадания Цикл
		Если Не РегламентноеЗаданиеДоступноПоФункциональнымОпциям(ОбъектМетаданных, ПараметрыРегламентныхЗаданий) Тогда
			ОтключенныеЗадания.Добавить(ОбъектМетаданных.Имя);
			Продолжить;
		КонецЕсли;
		
		Если Не ОбщегоНазначения.РазделениеВключено()
			И ПодсистемаРаботаВМоделиСервиса <> Неопределено Тогда
			
			ПараметрыЗадания = ПараметрыРегламентныхЗаданий.Найти(ОбъектМетаданных, "РегламентноеЗадание");
			
			Если ПараметрыЗадания <> Неопределено
				И ОбщегоНазначения.ЭтоАвтономноеРабочееМесто()
				И ПараметрыЗадания.ДоступноВАвтономномРабочемМесте = Истина Тогда
				Продолжить;
			КонецЕсли;
			
			Если ПодсистемаРаботаВМоделиСервиса.Состав.Содержит(ОбъектМетаданных) Тогда
				ОтключенныеЗадания.Добавить(ОбъектМетаданных.Имя);
				Продолжить;
			КонецЕсли;
			
			Для Каждого Подсистема Из ПодсистемаРаботаВМоделиСервиса.Подсистемы Цикл
				Если Подсистема.Состав.Содержит(ОбъектМетаданных) Тогда
					ОтключенныеЗадания.Добавить(ОбъектМетаданных.Имя);
					Продолжить;
				КонецЕсли;
			КонецЦикла;
		КонецЕсли;
	КонецЦикла;
	
	Если ИдентификаторРегламентногоЗадания = Неопределено Тогда
		
		Индекс = 0;
		Для Каждого Задание Из ТекущиеЗадания Цикл
			
			Идентификатор = Строка(Задание.УникальныйИдентификатор);
			
			Если Индекс >= Таблица.Количество() Или Таблица[Индекс].Идентификатор <> Идентификатор Тогда
				
				// Вставка нового задания.
				Обновляемое = Таблица.Вставить(Индекс);
				
				// Установка уникального идентификатора.
				Обновляемое.Идентификатор = Идентификатор;
			Иначе
				Обновляемое = Таблица[Индекс];
			КонецЕсли;
			
			Если ПараметризуемыеЗадания.Найти(Задание.Метаданные) <> Неопределено Тогда
				Обновляемое.Параметризуемое = Истина;
			КонецЕсли;
			
			УстановитьСвойстваРегламентногоЗадания(Обновляемое, Задание);
			Индекс = Индекс + 1;
		КонецЦикла;
	
		// Удаление лишних строк.
		Пока Индекс < Таблица.Количество() Цикл
			Таблица.Удалить(Индекс);
		КонецЦикла;
		Таблица.Сортировать("Наименование");
	Иначе
		Задание = РегламентныеЗадания.НайтиПоУникальномуИдентификатору(
			Новый УникальныйИдентификатор(ИдентификаторРегламентногоЗадания));
		
		Строки = Таблица.НайтиСтроки(
			Новый Структура("Идентификатор", ИдентификаторРегламентногоЗадания));
		
		Если Задание <> Неопределено
		   И Строки.Количество() > 0 Тогда
			
			СтрокаЗадание = Строки[0];
			Если ПараметризуемыеЗадания.Найти(Задание.Метаданные) <> Неопределено Тогда
				СтрокаЗадание.Параметризуемое = Истина;
			КонецЕсли;
			УстановитьСвойстваРегламентногоЗадания(СтрокаЗадание, Задание);
		КонецЕсли;
	КонецЕсли;
	
	Результат = Новый Структура;
	Результат.Вставить("Таблица", Таблица);
	Результат.Вставить("ОтключенныеЗадания", ОтключенныеЗадания);
	
	ПоместитьВоВременноеХранилище(Результат, АдресХранилища);
	
КонецПроцедуры

Процедура УстановитьСвойстваРегламентногоЗадания(Приемник, ЗаданиеИсточник)
	
	ЗаполнитьЗначенияСвойств(Приемник, ЗаданиеИсточник);
	
	// Уточнение наименования
	Приемник.Наименование = ПредставлениеРегламентногоЗадания(ЗаданиеИсточник);
	
	// Установка Даты завершения и Состояния завершения по последней фоновой процедуре.
	СвойстваПоследнегоФоновогоЗадания = СвойстваПоследнегоФоновогоЗаданияВыполненияРегламентногоЗадания(ЗаданиеИсточник);
	
	Приемник.ИмяЗадания = ЗаданиеИсточник.Метаданные.Имя;
	Если СвойстваПоследнегоФоновогоЗадания = Неопределено Тогда
		Приемник.ДатаНачала          = ТекстНеОпределено();
		Приемник.ДатаОкончания       = ТекстНеОпределено();
		Приемник.СостояниеВыполнения = ТекстНеОпределено();
	Иначе
		Приемник.ДатаНачала          = ?(ЗначениеЗаполнено(СвойстваПоследнегоФоновогоЗадания.Начало),
		                               СвойстваПоследнегоФоновогоЗадания.Начало,
		                               "<>");
		Приемник.ДатаОкончания       = ?(ЗначениеЗаполнено(СвойстваПоследнегоФоновогоЗадания.Конец),
		                               СвойстваПоследнегоФоновогоЗадания.Конец,
		                               "<>");
		Приемник.СостояниеВыполнения = СвойстваПоследнегоФоновогоЗадания.Состояние;
	КонецЕсли;
		
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Процедуры и функции для работы с регламентными заданиями.

// Предназначена для "ручного" немедленного выполнения процедуры регламентного задания
// либо в сеансе клиента (в файловой ИБ), либо в фоновом задании на сервере (в серверной ИБ).
// Применяется в любом режиме соединения.
// Ручной режим запуска не влияет на выполнение регламентного задания по аварийному
// и основному расписаниям, т.к. не указывается ссылка на регламентное задание у фонового задания.
// Тип ФоновоеЗадание не допускает установки такой ссылки, поэтому для файлового режима применяется
// тоже правило.
// 
// Параметры:
//  Задание             - РегламентноеЗадание
//                      - Строка - уникального идентификатора РегламентногоЗадания.
//
// Возвращаемое значение:
//  Структура:
//    * МоментЗапуска -   Неопределено
//                    -   Дата - для файловой ИБ устанавливает переданный момент, как момент запуска
//                        метода регламентного задания.
//                        Для серверной ИБ - возвращает момент запуска фонового задания по факту.
//    * ИдентификаторФоновогоЗадания - Строка - для серверной ИБ возвращает идентификатор запущенного фонового задания.
//
Функция ВыполнитьРегламентноеЗаданиеВручную(Знач Задание) Экспорт
	
	ВызватьИсключениеЕслиНетПраваАдминистрирования();
	УстановитьПривилегированныйРежим(Истина);
	
	ПараметрыВыполнения = ПараметрыВыполненияРегламентногоЗадания();
	ПараметрыВыполнения.ПроцедураУжеВыполняется = Ложь;
	Задание = РегламентныеЗаданияСервер.ПолучитьРегламентноеЗадание(Задание);
	
	ПараметрыВыполнения.ЗапускВыполнен = Ложь;
	СвойстваПоследнегоФоновогоЗадания = СвойстваПоследнегоФоновогоЗаданияВыполненияРегламентногоЗадания(Задание);
	
	Если СвойстваПоследнегоФоновогоЗадания <> Неопределено
	   И СвойстваПоследнегоФоновогоЗадания.Состояние = СостояниеФоновогоЗадания.Активно Тогда
		
		ПараметрыВыполнения.МоментЗапуска  = СвойстваПоследнегоФоновогоЗадания.Начало;
		Если ЗначениеЗаполнено(СвойстваПоследнегоФоновогоЗадания.Наименование) Тогда
			ПараметрыВыполнения.ПредставлениеФоновогоЗадания = СвойстваПоследнегоФоновогоЗадания.Наименование;
		Иначе
			ПараметрыВыполнения.ПредставлениеФоновогоЗадания = ПредставлениеРегламентногоЗадания(Задание);
		КонецЕсли;
	Иначе
		НаименованиеФоновогоЗадания = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Запуск вручную: %1'"), ПредставлениеРегламентногоЗадания(Задание));
		// Не используются длительные операции, т.к. делается вызов метода регламентного задания.
		ФоновоеЗадание = РасширенияКонфигурации.ВыполнитьФоновоеЗаданиеСРасширениямиБазыДанных(Задание.Метаданные.ИмяМетода, Задание.Параметры, Строка(Задание.УникальныйИдентификатор), НаименованиеФоновогоЗадания);
		ПараметрыВыполнения.ИдентификаторФоновогоЗадания = Строка(ФоновоеЗадание.УникальныйИдентификатор);
		ПараметрыВыполнения.МоментЗапуска = ФоновыеЗадания.НайтиПоУникальномуИдентификатору(ФоновоеЗадание.УникальныйИдентификатор).Начало;
		ПараметрыВыполнения.ЗапускВыполнен = Истина;
	КонецЕсли;
	
	ПараметрыВыполнения.ПроцедураУжеВыполняется = НЕ ПараметрыВыполнения.ЗапускВыполнен;
	Возврат ПараметрыВыполнения;
	
КонецФункции

Функция ПараметрыВыполненияРегламентногоЗадания() 
	
	Результат = Новый Структура;
	Результат.Вставить("МоментЗапуска");
	Результат.Вставить("ИдентификаторФоновогоЗадания");
	Результат.Вставить("ПредставлениеФоновогоЗадания");
	Результат.Вставить("ПроцедураУжеВыполняется");
	Результат.Вставить("ЗапускВыполнен");
	Возврат Результат;
	
КонецФункции

// Возвращает представление регламентного задания,
// это по порядку исключения незаполненных реквизитов:
// Наименование, Метаданные.Синоним, Метаданные.Имя.
//
// Параметры:
//  Задание      - РегламентноеЗадание
//               - Строка - если строка, тогда УникальныйИдентификатор строкой.
//
// Возвращаемое значение:
//  Строка
//
Функция ПредставлениеРегламентногоЗадания(Знач Задание) Экспорт
	
	ВызватьИсключениеЕслиНетПраваАдминистрирования();
	УстановитьПривилегированныйРежим(Истина);
	
	Если ТипЗнч(Задание) = Тип("РегламентноеЗадание") Тогда
		РегламентноеЗадание = Задание;
	Иначе
		РегламентноеЗадание = РегламентныеЗадания.НайтиПоУникальномуИдентификатору(Новый УникальныйИдентификатор(Задание));
	КонецЕсли;
	
	Если РегламентноеЗадание <> Неопределено Тогда
		Если РегламентноеЗадание.Предопределенное Тогда
			Представление = РегламентноеЗадание.Метаданные.Синоним;
		Иначе
			Представление = РегламентноеЗадание.Наименование;
			
			Если ПустаяСтрока(РегламентноеЗадание.Наименование) Тогда
				Представление = РегламентноеЗадание.Метаданные.Синоним;
			КонецЕсли;
		КонецЕсли;
		Если ПустаяСтрока(Представление) Тогда
			Представление = РегламентноеЗадание.Метаданные.Имя;
		КонецЕсли
	Иначе
		Представление = ТекстНеОпределено();
	КонецЕсли;
	
	Возврат Представление;
	
КонецФункции

// Возвращает текст "<не определено>".
Функция ТекстНеОпределено() Экспорт
	
	Возврат НСтр("ru = '<не определено>'");
	
КонецФункции

// Возвращает многострочную Строку содержащую Сообщения и ОписаниеИнформацииОбОшибке,
// последнее фоновое задание найдено по идентификатору регламентного задания
// и сообщения/ошибки есть.
//
// Параметры:
//  Задание      - РегламентноеЗадание
//               - Строка - УникальныйИдентификатор
//                 РегламентногоЗадания строкой.
//
// Возвращаемое значение:
//  Строка
//
Функция СообщенияИОписанияОшибокРегламентногоЗадания(Знач Задание) Экспорт
	
	ВызватьИсключениеЕслиНетПраваАдминистрирования();
	УстановитьПривилегированныйРежим(Истина);

	ИдентификаторРегламентногоЗадания = ?(ТипЗнч(Задание) = Тип("РегламентноеЗадание"), Строка(Задание.УникальныйИдентификатор), Задание);
	СвойстваПоследнегоФоновогоЗадания = СвойстваПоследнегоФоновогоЗаданияВыполненияРегламентногоЗадания(ИдентификаторРегламентногоЗадания);
	Возврат ?(СвойстваПоследнегоФоновогоЗадания = Неопределено,
	          "",
	          СообщенияИОписанияОшибокФоновогоЗадания(СвойстваПоследнегоФоновогоЗадания.Идентификатор));
	
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Процедуры и функции для работы с фоновыми заданиями.

// Отменяет фоновое задание, если это возможно, а именно, если оно выполняется на сервере, и активно.
//
// Параметры:
//  Идентификатор  - строка уникального идентификатора ФоновогоЗадания.
// 
Процедура ОтменитьФоновоеЗадание(Идентификатор) Экспорт
	
	ВызватьИсключениеЕслиНетПраваАдминистрирования();
	УстановитьПривилегированныйРежим(Истина);
	
	НовыйУникальныйИдентификатор = Новый УникальныйИдентификатор(Идентификатор);
	Отбор = Новый Структура;
	Отбор.Вставить("УникальныйИдентификатор", НовыйУникальныйИдентификатор);
	МассивФоновыхЗаданий = ФоновыеЗадания.ПолучитьФоновыеЗадания(Отбор);
	Если МассивФоновыхЗаданий.Количество() = 1 Тогда
		ФоновоеЗадание = МассивФоновыхЗаданий[0];
	Иначе
		ВызватьИсключение НСтр("ru = 'Фоновое задание не существует.'");
	КонецЕсли;
	
	Если ФоновоеЗадание.Состояние <> СостояниеФоновогоЗадания.Активно Тогда
		ВызватьИсключение НСтр("ru = 'Задание не выполняется, его нельзя отменить.'");
	КонецЕсли;
	
	ФоновоеЗадание.Отменить();
	
КонецПроцедуры

// Только для внутреннего использования.
//
Процедура ЗаполнитьТаблицуСвойствФоновыхЗаданийВФоне(Параметры, АдресХранилища) Экспорт
	
	ТаблицаСвойств = СвойстваФоновыхЗаданий(Параметры.Отбор);
	
	Результат = Новый Структура;
	Результат.Вставить("ТаблицаСвойств", ТаблицаСвойств);
	
	ПоместитьВоВременноеХранилище(Результат, АдресХранилища);
	
КонецПроцедуры

// Возвращает свойства ФоновогоЗадания по строке уникального идентификатора.
//
// Параметры:
//  Идентификатор - Строка - уникального идентификатора ФоновогоЗадания.
//  ИменаСвойств  - Строка - если заполнено, возвращается структура с указанными свойствами.
// 
// Возвращаемое значение:
//  СтрокаТаблицыЗначений, Структура - свойства ФоновогоЗадания.
//
Функция ПолучитьСвойстваФоновогоЗадания(Идентификатор, ИменаСвойств = "") Экспорт
	
	ВызватьИсключениеЕслиНетПраваАдминистрирования();
	УстановитьПривилегированныйРежим(Истина);
	
	Отбор = Новый Структура("Идентификатор", Идентификатор);
	ТаблицаСвойствФоновыхЗаданий = СвойстваФоновыхЗаданий(Отбор);
	
	Если ТаблицаСвойствФоновыхЗаданий.Количество() > 0 Тогда
		Если ЗначениеЗаполнено(ИменаСвойств) Тогда
			Результат = Новый Структура(ИменаСвойств);
			ЗаполнитьЗначенияСвойств(Результат, ТаблицаСвойствФоновыхЗаданий[0]);
		Иначе
			Результат = ТаблицаСвойствФоновыхЗаданий[0];
		КонецЕсли;
	Иначе
		Результат = Неопределено;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Возвращает свойства последнего фонового задания выполненного при выполнении регламентного задания, если оно есть.
// Процедура работает, как в файл-серверном, так и в клиент-серверном режимах.
//
// Параметры:
//  РегламентноеЗадание - РегламентноеЗадание
//                      - Строка - строка уникального идентификатора РегламентногоЗадания.
//
// Возвращаемое значение:
//  СтрокаТаблицыЗначений:
//     * Идентификатор - Строка
//     * Наименование - Строка
//     * Ключ - Строка
//     * Конец - Дата
//     * ИдентификаторРегламентногоЗадания - Строка
//     * Состояние - СостояниеФоновогоЗадания
//     * ИмяМетода - Строка
//     * Расположение - Строка
//     * ОписаниеИнформацииОбОшибке - Строка
//     * ПопыткаЗапуска - Число
//     * СообщенияПользователю - Массив
//     * НомерСеанса - Число
//     * НачалоСеанса - Дата
//
Функция СвойстваПоследнегоФоновогоЗаданияВыполненияРегламентногоЗадания(РегламентноеЗадание)
	
	ВызватьИсключениеЕслиНетПраваАдминистрирования();
	УстановитьПривилегированныйРежим(Истина);
	
	ИдентификаторРегламентногоЗадания = ?(ТипЗнч(РегламентноеЗадание) = Тип("РегламентноеЗадание"), Строка(РегламентноеЗадание.УникальныйИдентификатор), РегламентноеЗадание);
	Отбор = Новый Структура;
	Отбор.Вставить("ИдентификаторРегламентногоЗадания", ИдентификаторРегламентногоЗадания);
	Отбор.Вставить("ПолучитьПоследнееФоновоеЗаданиеРегламентногоЗадания");
	ТаблицаСвойствФоновыхЗаданий = СвойстваФоновыхЗаданий(Отбор);
	ТаблицаСвойствФоновыхЗаданий.Сортировать("Конец Возр");
	
	Если ТаблицаСвойствФоновыхЗаданий.Количество() = 0 Тогда
		СвойстваФоновогоЗадания = Неопределено;
	ИначеЕсли НЕ ЗначениеЗаполнено(ТаблицаСвойствФоновыхЗаданий[0].Конец) Тогда
		СвойстваФоновогоЗадания = ТаблицаСвойствФоновыхЗаданий[0];
	Иначе
		СвойстваФоновогоЗадания = ТаблицаСвойствФоновыхЗаданий[ТаблицаСвойствФоновыхЗаданий.Количество()-1];
	КонецЕсли;
	
	Возврат СвойстваФоновогоЗадания;
	
КонецФункции

// Возвращает многострочную Строку содержащую Сообщения и ОписаниеИнформацииОбОшибке,
// если фоновое задание найдено по идентификатору и сообщения/ошибки есть.
//
// Параметры:
//  Задание      - Строка - УникальныйИдентификатор ФоновогоЗадания строкой.
//
// Возвращаемое значение:
//  Строка
//
Функция СообщенияИОписанияОшибокФоновогоЗадания(Идентификатор, СвойстваФоновогоЗадания = Неопределено) Экспорт
	
	ВызватьИсключениеЕслиНетПраваАдминистрирования();
	УстановитьПривилегированныйРежим(Истина);
	
	Если СвойстваФоновогоЗадания = Неопределено Тогда
		СвойстваФоновогоЗадания = ПолучитьСвойстваФоновогоЗадания(Идентификатор);
	КонецЕсли;
	
	Строка = "";
	Если СвойстваФоновогоЗадания <> Неопределено Тогда
		Для каждого Сообщение Из СвойстваФоновогоЗадания.СообщенияПользователю Цикл
			Строка = Строка + ?(Строка = "",
			                    "",
			                    "
			                    |
			                    |") + Сообщение.Текст;
		КонецЦикла;
		Если ЗначениеЗаполнено(СвойстваФоновогоЗадания.ОписаниеИнформацииОбОшибке) Тогда
			Строка = Строка + ?(Строка = "",
			                    СвойстваФоновогоЗадания.ОписаниеИнформацииОбОшибке,
			                    "
			                    |
			                    |" + СвойстваФоновогоЗадания.ОписаниеИнформацииОбОшибке);
		КонецЕсли;
	КонецЕсли;
	
	Возврат Строка;
	
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Вспомогательные процедуры и функции.

Процедура ИзменитьИспользованиеРегламентныхЗаданийПоФункциональнымОпциям(Источник, Знач Использование)
	
	Если Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
		Возврат;
	КонецЕсли;
	
	ТипИсточника = ТипЗнч(Источник);
	ХранениеФО = Метаданные.НайтиПоТипу(ТипИсточника);
	ФункциональнаяОпция = Неопределено;
	ЭтоПодчиненныйУзелРИБ = ОбщегоНазначения.ЭтоПодчиненныйУзелРИБ();
	ЭтоАвтономноеРабочееМесто = ОбщегоНазначения.ЭтоАвтономноеРабочееМесто();
	
	ЗависимыеРегламентныеЗадания = РегламентныеЗаданияЗависимыеОтФункциональныхОпций();
	
	СписокФО = ЗависимыеРегламентныеЗадания.Скопировать(,"ФункциональнаяОпция");
	СписокФО.Свернуть("ФункциональнаяОпция");
	
	Для Каждого СтрокаФО Из СписокФО Цикл
		
		Если СтрокаФО.ФункциональнаяОпция = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		
		Если СтрокаФО.ФункциональнаяОпция.Хранение = ХранениеФО Тогда
			ФункциональнаяОпция = СтрокаФО.ФункциональнаяОпция; // ОбъектМетаданныхФункциональнаяОпция
			Прервать;
		КонецЕсли;
		
	КонецЦикла;
	
	Если ФункциональнаяОпция = Неопределено
		Или ПолучитьФункциональнуюОпцию(ФункциональнаяОпция.Имя) = Использование Тогда
		Возврат;
	КонецЕсли;
	
	Задания = ЗависимыеРегламентныеЗадания.Скопировать(Новый Структура("ФункциональнаяОпция", ФункциональнаяОпция) ,"РегламентноеЗадание");
	Задания.Свернуть("РегламентноеЗадание");
	
	Для Каждого СтрокаЗадание Из Задания Цикл
		
		ИспользованиеПоФО                = Неопределено;
		ОтключитьЗадание                 = Истина;
		ОтключитьВПодчиненномУзлеРИБ     = Ложь;
		ОтключитьВАвтономномРабочемМесте = Ложь;
		
		НайденныеСтроки = ЗависимыеРегламентныеЗадания.НайтиСтроки(Новый Структура("РегламентноеЗадание", СтрокаЗадание.РегламентноеЗадание));
		
		Для Каждого СтрокаЗависимости Из НайденныеСтроки Цикл
			ОтключитьВПодчиненномУзлеРИБ = (СтрокаЗависимости.ДоступноВПодчиненномУзлеРИБ = Ложь) И ЭтоПодчиненныйУзелРИБ;
			ОтключитьВАвтономномРабочемМесте = (СтрокаЗависимости.ДоступноВАвтономномРабочемМесте = Ложь) И ЭтоАвтономноеРабочееМесто;
			Если ОтключитьВПодчиненномУзлеРИБ Или ОтключитьВАвтономномРабочемМесте Тогда
				Прервать;
			КонецЕсли;
			
			Если СтрокаЗависимости.ФункциональнаяОпция = Неопределено Тогда
				Продолжить;
			КонецЕсли;
			
			Если СтрокаЗависимости.ФункциональнаяОпция = ФункциональнаяОпция Тогда
				ЗначениеФО = Использование;
			Иначе
				ЗначениеФО = ПолучитьФункциональнуюОпцию(СтрокаЗависимости.ФункциональнаяОпция.Имя);
			КонецЕсли;
			
			Если СтрокаЗависимости.ВключатьПриВключенииФункциональнойОпции = Ложь Тогда
				Если ОтключитьЗадание Тогда
					ОтключитьЗадание = Не ЗначениеФО;
				КонецЕсли;
				ЗначениеФО = Ложь;
			КонецЕсли;
			
			Если ИспользованиеПоФО = Неопределено Тогда
				ИспользованиеПоФО = ЗначениеФО;
			ИначеЕсли СтрокаЗависимости.ЗависимостьПоИ Тогда
				ИспользованиеПоФО = ИспользованиеПоФО И ЗначениеФО;
			Иначе
				ИспользованиеПоФО = ИспользованиеПоФО Или ЗначениеФО;
			КонецЕсли;
		КонецЦикла;
		
		Если ОтключитьВПодчиненномУзлеРИБ Или ОтключитьВАвтономномРабочемМесте Тогда
			Использование = Ложь;
		Иначе
			Если Использование <> ИспользованиеПоФО Тогда
				Продолжить;
			КонецЕсли;
			
			Если Не Использование И Не ОтключитьЗадание Тогда
				Продолжить;
			КонецЕсли;
		КонецЕсли;
		
		СписокЗаданий = РегламентныеЗаданияСервер.НайтиЗадания(Новый Структура("Метаданные", СтрокаЗадание.РегламентноеЗадание));
		Для Каждого РегламентноеЗадание Из СписокЗаданий Цикл
			ПараметрыЗадания = Новый Структура("Использование", Использование);
			РегламентныеЗаданияСервер.ИзменитьЗадание(РегламентноеЗадание, ПараметрыЗадания);
		КонецЦикла;
		
	КонецЦикла;
	
КонецПроцедуры

// Возвращает новую таблицу свойств фоновых заданий.
//
// Возвращаемое значение:
//  ТаблицаЗначений:
//     * Идентификатор - Строка
//     * Наименование - Строка
//     * Ключ - Строка
//     * Конец - Дата
//     * ИдентификаторРегламентногоЗадания - Строка
//     * Состояние - СостояниеФоновогоЗадания
//     * ИмяМетода - Строка
//     * Расположение - Строка
//     * ОписаниеИнформацииОбОшибке - Строка
//     * ПопыткаЗапуска - Число
//     * СообщенияПользователю - Массив
//     * НомерСеанса - Число
//     * НачалоСеанса - Дата
//
Функция НовыеСвойстваФоновыхЗаданий()
	
	НоваяТаблица = Новый ТаблицаЗначений;
	НоваяТаблица.Колонки.Добавить("Идентификатор",                     Новый ОписаниеТипов("Строка"));
	НоваяТаблица.Колонки.Добавить("Наименование",                      Новый ОписаниеТипов("Строка"));
	НоваяТаблица.Колонки.Добавить("Ключ",                              Новый ОписаниеТипов("Строка"));
	НоваяТаблица.Колонки.Добавить("Начало",                            Новый ОписаниеТипов("Дата"));
	НоваяТаблица.Колонки.Добавить("Конец",                             Новый ОписаниеТипов("Дата"));
	НоваяТаблица.Колонки.Добавить("ИдентификаторРегламентногоЗадания", Новый ОписаниеТипов("Строка"));
	НоваяТаблица.Колонки.Добавить("Состояние",                         Новый ОписаниеТипов("СостояниеФоновогоЗадания"));
	НоваяТаблица.Колонки.Добавить("ИмяМетода",                         Новый ОписаниеТипов("Строка"));
	НоваяТаблица.Колонки.Добавить("Расположение",                      Новый ОписаниеТипов("Строка"));
	НоваяТаблица.Колонки.Добавить("ОписаниеИнформацииОбОшибке",        Новый ОписаниеТипов("Строка"));
	НоваяТаблица.Колонки.Добавить("ПопыткаЗапуска",                    Новый ОписаниеТипов("Число"));
	НоваяТаблица.Колонки.Добавить("СообщенияПользователю",             Новый ОписаниеТипов("Массив"));
	НоваяТаблица.Колонки.Добавить("НомерСеанса",                       Новый ОписаниеТипов("Число"));
	НоваяТаблица.Колонки.Добавить("НачалоСеанса",                      Новый ОписаниеТипов("Дата"));
	НоваяТаблица.Индексы.Добавить("Идентификатор, Начало");
	
	Возврат НоваяТаблица;
	
КонецФункции

Процедура ДобавитьСвойстваФоновыхЗаданий(Знач МассивФоновыхЗаданий, Знач ТаблицаСвойствФоновыхЗаданий)
	
	Индекс = МассивФоновыхЗаданий.Количество() - 1;
	Пока Индекс >= 0 Цикл
		ФоновоеЗадание = МассивФоновыхЗаданий[Индекс]; // ФоновоеЗадание
		Строка = ТаблицаСвойствФоновыхЗаданий.Добавить();
		ЗаполнитьЗначенияСвойств(Строка, ФоновоеЗадание);
		Строка.Идентификатор = ФоновоеЗадание.УникальныйИдентификатор;
		РегламентноеЗадание = ФоновоеЗадание.РегламентноеЗадание;
		
		Если РегламентноеЗадание = Неопределено
		   И СтроковыеФункцииКлиентСервер.ЭтоУникальныйИдентификатор(ФоновоеЗадание.Ключ) Тогда
			
			РегламентноеЗадание = РегламентныеЗадания.НайтиПоУникальномуИдентификатору(Новый УникальныйИдентификатор(ФоновоеЗадание.Ключ));
		КонецЕсли;
		Строка.ИдентификаторРегламентногоЗадания = ?(
			РегламентноеЗадание = Неопределено,
			"",
			РегламентноеЗадание.УникальныйИдентификатор);
		
		Строка.ОписаниеИнформацииОбОшибке = ?(
			ФоновоеЗадание.ИнформацияОбОшибке = Неопределено,
			"",
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(ФоновоеЗадание.ИнформацияОбОшибке));
		
		Индекс = Индекс - 1;
	КонецЦикла;
	
КонецПроцедуры

#КонецОбласти
